Add back GtkTimeline
authorOwen W. Taylor <otaylor@fishsoup.net>
Fri, 27 Jul 2012 08:56:51 +0000 (04:56 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 14 Feb 2013 22:19:49 +0000 (17:19 -0500)
Add back the GtkTimeline code that previously made private and
then removed. It will be hooked up to GdkFrameClock. This commit
purely adds the old code back.

https://bugzilla.gnome.org/show_bug.cgi?id=685460

gtk/Makefile.am
gtk/gtktimeline.c [new file with mode: 0644]
gtk/gtktimeline.h [new file with mode: 0644]

index 973f3c8994da1470e71f8e55c8f6a49d44ecb050..70ef2049ef3357ea816e7e9d54c52dba6b18be1a 100644 (file)
@@ -544,6 +544,7 @@ gtk_private_h_sources =             \
        gtktextutil.h           \
        gtkthemingbackgroundprivate.h \
        gtkthemingengineprivate.h \
+       gtktimeline.h           \
        gtktoolpaletteprivate.h \
        gtktreedatalist.h       \
        gtktreeprivate.h        \
@@ -850,6 +851,7 @@ gtk_base_c_sources =                \
        gtktextview.c           \
        gtkthemingbackground.c  \
        gtkthemingengine.c      \
+       gtktimeline.c           \
        gtktoggleaction.c       \
        gtktogglebutton.c       \
        gtktoggletoolbutton.c   \
diff --git a/gtk/gtktimeline.c b/gtk/gtktimeline.c
new file mode 100644 (file)
index 0000000..2202e79
--- /dev/null
@@ -0,0 +1,760 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtktimeline.h>
+#include <gtk/gtktypebuiltins.h>
+#include <gtk/gtksettings.h>
+#include <math.h>
+
+#define MSECS_PER_SEC 1000
+#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes)
+#define DEFAULT_FPS 30
+
+typedef struct GtkTimelinePriv GtkTimelinePriv;
+
+struct GtkTimelinePriv
+{
+  guint duration;
+  guint fps;
+  guint source_id;
+
+  GTimer *timer;
+  gdouble elapsed_time;
+
+  gdouble progress;
+  gdouble last_progress;
+
+  GdkScreen *screen;
+
+  GtkTimelineProgressType progress_type;
+
+  guint animations_enabled : 1;
+  guint loop               : 1;
+  guint direction          : 1;
+};
+
+enum {
+  PROP_0,
+  PROP_FPS,
+  PROP_DURATION,
+  PROP_LOOP,
+  PROP_DIRECTION,
+  PROP_SCREEN
+};
+
+enum {
+  STARTED,
+  PAUSED,
+  FINISHED,
+  FRAME,
+  LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+
+static void  gtk_timeline_set_property  (GObject         *object,
+                                         guint            prop_id,
+                                         const GValue    *value,
+                                         GParamSpec      *pspec);
+static void  gtk_timeline_get_property  (GObject         *object,
+                                         guint            prop_id,
+                                         GValue          *value,
+                                         GParamSpec      *pspec);
+static void  gtk_timeline_finalize      (GObject *object);
+
+
+G_DEFINE_TYPE (GtkTimeline, gtk_timeline, G_TYPE_OBJECT)
+
+
+static void
+gtk_timeline_class_init (GtkTimelineClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = gtk_timeline_set_property;
+  object_class->get_property = gtk_timeline_get_property;
+  object_class->finalize = gtk_timeline_finalize;
+
+  g_object_class_install_property (object_class,
+                                   PROP_FPS,
+                                   g_param_spec_uint ("fps",
+                                                      "FPS",
+                                                      "Frames per second for the timeline",
+                                                      1, G_MAXUINT,
+                                                      DEFAULT_FPS,
+                                                      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_DURATION,
+                                   g_param_spec_uint ("duration",
+                                                      "Animation Duration",
+                                                      "Animation Duration",
+                                                      0, G_MAXUINT,
+                                                      0,
+                                                      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_LOOP,
+                                   g_param_spec_boolean ("loop",
+                                                         "Loop",
+                                                         "Whether the timeline loops or not",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_SCREEN,
+                                   g_param_spec_object ("screen",
+                                                        "Screen",
+                                                        "Screen to get the settings from",
+                                                        GDK_TYPE_SCREEN,
+                                                        G_PARAM_READWRITE));
+
+  signals[STARTED] =
+    g_signal_new ("started",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkTimelineClass, started),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[PAUSED] =
+    g_signal_new ("paused",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkTimelineClass, paused),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[FINISHED] =
+    g_signal_new ("finished",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkTimelineClass, finished),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[FRAME] =
+    g_signal_new ("frame",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkTimelineClass, frame),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__DOUBLE,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_DOUBLE);
+
+  g_type_class_add_private (klass, sizeof (GtkTimelinePriv));
+}
+
+static void
+gtk_timeline_init (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  priv = timeline->priv = G_TYPE_INSTANCE_GET_PRIVATE (timeline,
+                                                       GTK_TYPE_TIMELINE,
+                                                       GtkTimelinePriv);
+
+  priv->fps = DEFAULT_FPS;
+  priv->duration = 0.0;
+  priv->direction = GTK_TIMELINE_DIRECTION_FORWARD;
+  priv->screen = gdk_screen_get_default ();
+
+  priv->last_progress = 0;
+}
+
+static void
+gtk_timeline_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  GtkTimeline *timeline;
+
+  timeline = GTK_TIMELINE (object);
+
+  switch (prop_id)
+    {
+    case PROP_FPS:
+      _gtk_timeline_set_fps (timeline, g_value_get_uint (value));
+      break;
+    case PROP_DURATION:
+      gtk_timeline_set_duration (timeline, g_value_get_uint (value));
+      break;
+    case PROP_LOOP:
+      gtk_timeline_set_loop (timeline, g_value_get_boolean (value));
+      break;
+    case PROP_DIRECTION:
+      gtk_timeline_set_direction (timeline, g_value_get_enum (value));
+      break;
+    case PROP_SCREEN:
+      gtk_timeline_set_screen (timeline,
+                               GDK_SCREEN (g_value_get_object (value)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_timeline_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  GtkTimeline *timeline;
+  GtkTimelinePriv *priv;
+
+  timeline = GTK_TIMELINE (object);
+  priv = timeline->priv;
+
+  switch (prop_id)
+    {
+    case PROP_FPS:
+      g_value_set_uint (value, priv->fps);
+      break;
+    case PROP_DURATION:
+      g_value_set_uint (value, priv->duration);
+      break;
+    case PROP_LOOP:
+      g_value_set_boolean (value, priv->loop);
+      break;
+    case PROP_DIRECTION:
+      g_value_set_enum (value, priv->direction);
+      break;
+    case PROP_SCREEN:
+      g_value_set_object (value, priv->screen);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_timeline_finalize (GObject *object)
+{
+  GtkTimelinePriv *priv;
+  GtkTimeline *timeline;
+
+  timeline = (GtkTimeline *) object;
+  priv = timeline->priv;
+
+  if (priv->source_id)
+    {
+      g_source_remove (priv->source_id);
+      priv->source_id = 0;
+    }
+
+  if (priv->timer)
+    g_timer_destroy (priv->timer);
+
+  G_OBJECT_CLASS (gtk_timeline_parent_class)->finalize (object);
+}
+
+static gdouble
+calculate_progress (gdouble                 linear_progress,
+                    GtkTimelineProgressType progress_type)
+{
+  gdouble progress;
+
+  progress = linear_progress;
+
+  switch (progress_type)
+    {
+    case GTK_TIMELINE_PROGRESS_LINEAR:
+      break;
+    case GTK_TIMELINE_PROGRESS_EASE_IN_OUT:
+      progress *= 2;
+
+      if (progress < 1)
+        progress = pow (progress, 3) / 2;
+      else
+        progress = (pow (progress - 2, 3) + 2) / 2;
+
+      break;
+    case GTK_TIMELINE_PROGRESS_EASE:
+      progress = (sin ((progress - 0.5) * G_PI) + 1) / 2;
+      break;
+    case GTK_TIMELINE_PROGRESS_EASE_IN:
+      progress = pow (progress, 3);
+      break;
+    case GTK_TIMELINE_PROGRESS_EASE_OUT:
+      progress = pow (progress - 1, 3) + 1;
+      break;
+    default:
+      g_warning ("Timeline progress type not implemented");
+    }
+
+  return progress;
+}
+
+static gboolean
+gtk_timeline_run_frame (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+  gdouble delta_progress, progress;
+
+  /* the user may unref us during the signals, so save ourselves */
+  g_object_ref (timeline);
+
+  priv = timeline->priv;
+
+  priv->elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
+  g_timer_start (priv->timer);
+
+  if (priv->animations_enabled)
+    {
+      delta_progress = (gdouble) priv->elapsed_time / priv->duration;
+      progress = priv->last_progress;
+
+      if (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD)
+        progress -= delta_progress;
+      else
+        progress += delta_progress;
+
+      priv->last_progress = progress;
+
+      progress = CLAMP (progress, 0., 1.);
+    }
+  else
+    progress = (priv->direction == GTK_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0;
+
+  priv->progress = progress;
+  g_signal_emit (timeline, signals [FRAME], 0,
+                 calculate_progress (progress, priv->progress_type));
+
+  if ((priv->direction == GTK_TIMELINE_DIRECTION_FORWARD && progress == 1.0) ||
+      (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD && progress == 0.0))
+    {
+      gboolean loop;
+
+      loop = priv->loop && priv->animations_enabled;
+
+      if (loop)
+        gtk_timeline_rewind (timeline);
+      else
+        {
+          if (priv->source_id)
+            {
+              g_source_remove (priv->source_id);
+              priv->source_id = 0;
+            }
+          g_timer_stop (priv->timer);
+          g_signal_emit (timeline, signals [FINISHED], 0);
+          g_object_unref (timeline);
+          return FALSE;
+        }
+    }
+
+  g_object_unref (timeline);
+
+  return TRUE;
+}
+
+/*
+ * gtk_timeline_new:
+ * @duration: duration in milliseconds for the timeline
+ *
+ * Creates a new #GtkTimeline with the specified number of frames.
+ *
+ * Return Value: the newly created #GtkTimeline
+ */
+GtkTimeline *
+gtk_timeline_new (guint duration)
+{
+  return g_object_new (GTK_TYPE_TIMELINE,
+                       "duration", duration,
+                       NULL);
+}
+
+GtkTimeline *
+gtk_timeline_new_for_screen (guint      duration,
+                              GdkScreen *screen)
+{
+  return g_object_new (GTK_TYPE_TIMELINE,
+                       "duration", duration,
+                       "screen", screen,
+                       NULL);
+}
+
+/*
+ * gtk_timeline_start:
+ * @timeline: A #GtkTimeline
+ *
+ * Runs the timeline from the current frame.
+ */
+void
+gtk_timeline_start (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+  GtkSettings *settings;
+  gboolean enable_animations = FALSE;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+
+  if (!priv->source_id)
+    {
+      if (priv->timer)
+        g_timer_continue (priv->timer);
+      else
+        priv->timer = g_timer_new ();
+
+      /* sanity check */
+      g_assert (priv->fps > 0);
+
+      if (priv->screen)
+        {
+          settings = gtk_settings_get_for_screen (priv->screen);
+          g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
+        }
+
+      priv->animations_enabled = enable_animations;
+
+      g_signal_emit (timeline, signals [STARTED], 0);
+
+      if (enable_animations)
+        priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps),
+                                                   (GSourceFunc) gtk_timeline_run_frame,
+                                                   timeline);
+      else
+        priv->source_id = gdk_threads_add_idle ((GSourceFunc) gtk_timeline_run_frame,
+                                                timeline);
+    }
+}
+
+/*
+ * gtk_timeline_pause:
+ * @timeline: A #GtkTimeline
+ *
+ * Pauses the timeline.
+ */
+void
+gtk_timeline_pause (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+
+  if (priv->source_id)
+    {
+      g_timer_stop (priv->timer);
+      g_source_remove (priv->source_id);
+      priv->source_id = 0;
+      g_signal_emit (timeline, signals [PAUSED], 0);
+    }
+}
+
+/*
+ * gtk_timeline_rewind:
+ * @timeline: A #GtkTimeline
+ *
+ * Rewinds the timeline.
+ */
+void
+gtk_timeline_rewind (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+
+  if (gtk_timeline_get_direction (timeline) != GTK_TIMELINE_DIRECTION_FORWARD)
+    priv->progress = priv->last_progress = 1.;
+  else
+    priv->progress = priv->last_progress = 0.;
+
+  /* reset timer */
+  if (priv->timer)
+    {
+      g_timer_start (priv->timer);
+
+      if (!priv->source_id)
+        g_timer_stop (priv->timer);
+    }
+}
+
+/*
+ * gtk_timeline_is_running:
+ * @timeline: A #GtkTimeline
+ *
+ * Returns whether the timeline is running or not.
+ *
+ * Return Value: %TRUE if the timeline is running
+ */
+gboolean
+gtk_timeline_is_running (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), FALSE);
+
+  priv = timeline->priv;
+
+  return (priv->source_id != 0);
+}
+
+/*
+ * gtk_timeline_get_elapsed_time:
+ * @timeline: A #GtkTimeline
+ *
+ * Returns the elapsed time since the last GtkTimeline::frame signal
+ *
+ * Return Value: elapsed time in milliseconds since the last frame
+ */
+guint
+gtk_timeline_get_elapsed_time (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0);
+
+  priv = timeline->priv;
+  return priv->elapsed_time;
+}
+
+/*
+ * gtk_timeline_get_fps:
+ * @timeline: A #GtkTimeline
+ *
+ * Returns the number of frames per second.
+ *
+ * Return Value: frames per second
+ */
+guint
+gtk_timeline_get_fps (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 1);
+
+  priv = timeline->priv;
+  return priv->fps;
+}
+
+/*
+ * gtk_timeline_set_fps:
+ * @timeline: A #GtkTimeline
+ * @fps: frames per second
+ *
+ * Sets the number of frames per second that
+ * the timeline will play.
+ */
+void
+gtk_timeline_set_fps (GtkTimeline *timeline,
+                      guint        fps)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+  g_return_if_fail (fps > 0);
+
+  priv = timeline->priv;
+
+  priv->fps = fps;
+
+  if (gtk_timeline_is_running (timeline))
+    {
+      g_source_remove (priv->source_id);
+      priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps),
+                                                 (GSourceFunc) gtk_timeline_run_frame,
+                                                 timeline);
+    }
+
+  g_object_notify (G_OBJECT (timeline), "fps");
+}
+
+/**
+ * gtk_timeline_get_loop:
+ * @timeline: A #GtkTimeline
+ *
+ * Returns whether the timeline loops to the
+ * beginning when it has reached the end.
+ *
+ * Return Value: %TRUE if the timeline loops
+ */
+gboolean
+gtk_timeline_get_loop (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), FALSE);
+
+  priv = timeline->priv;
+  return priv->loop;
+}
+
+/*
+ * gtk_timeline_set_loop:
+ * @timeline: A #GtkTimeline
+ * @loop: %TRUE to make the timeline loop
+ *
+ * Sets whether the timeline loops to the beginning
+ * when it has reached the end.
+ */
+void
+gtk_timeline_set_loop (GtkTimeline *timeline,
+                        gboolean     loop)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+
+  if (loop != priv->loop)
+    {
+      priv->loop = loop;
+      g_object_notify (G_OBJECT (timeline), "loop");
+    }
+}
+
+void
+gtk_timeline_set_duration (GtkTimeline *timeline,
+                            guint        duration)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+
+  if (duration != priv->duration)
+    {
+      priv->duration = duration;
+      g_object_notify (G_OBJECT (timeline), "duration");
+    }
+}
+
+guint
+gtk_timeline_get_duration (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0);
+
+  priv = timeline->priv;
+
+  return priv->duration;
+}
+
+/*
+ * gtk_timeline_set_direction:
+ * @timeline: A #GtkTimeline
+ * @direction: direction
+ *
+ * Sets the direction of the timeline.
+ */
+void
+gtk_timeline_set_direction (GtkTimeline          *timeline,
+                             GtkTimelineDirection  direction)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+  priv->direction = direction;
+}
+
+/*
+ * gtk_timeline_get_direction:
+ * @timeline: A #GtkTimeline
+ *
+ * Returns the direction of the timeline.
+ *
+ * Return Value: direction
+ */
+GtkTimelineDirection
+gtk_timeline_get_direction (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), GTK_TIMELINE_DIRECTION_FORWARD);
+
+  priv = timeline->priv;
+  return priv->direction;
+}
+
+void
+gtk_timeline_set_screen (GtkTimeline *timeline,
+                         GdkScreen   *screen)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+
+  priv = timeline->priv;
+
+  if (priv->screen)
+    g_object_unref (priv->screen);
+
+  priv->screen = g_object_ref (screen);
+
+  g_object_notify (G_OBJECT (timeline), "screen");
+}
+
+GdkScreen *
+gtk_timeline_get_screen (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), NULL);
+
+  priv = timeline->priv;
+  return priv->screen;
+}
+
+gdouble
+gtk_timeline_get_progress (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0.);
+
+  priv = timeline->priv;
+  return calculate_progress (priv->progress, priv->progress_type);
+}
+
+GtkTimelineProgressType
+gtk_timeline_get_progress_type (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), GTK_TIMELINE_PROGRESS_LINEAR);
+
+  priv = timeline->priv;
+  return priv->progress_type;
+}
+
+void
+gtk_timeline_set_progress_type (GtkTimeline             *timeline,
+                                GtkTimelineProgressType  progress_type)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+  priv->progress_type = progress_type;
+}
diff --git a/gtk/gtktimeline.h b/gtk/gtktimeline.h
new file mode 100644 (file)
index 0000000..3960cb7
--- /dev/null
@@ -0,0 +1,116 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_TIMELINE_H__
+#define __GTK_TIMELINE_H__
+
+#include <glib-object.h>
+#include <gtk/gtkenums.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_TIMELINE                 (gtk_timeline_get_type ())
+#define GTK_TIMELINE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TIMELINE, GtkTimeline))
+#define GTK_TIMELINE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TIMELINE, GtkTimelineClass))
+#define GTK_IS_TIMELINE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TIMELINE))
+#define GTK_IS_TIMELINE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TIMELINE))
+#define GTK_TIMELINE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TIMELINE, GtkTimelineClass))
+
+typedef struct GtkTimeline      GtkTimeline;
+typedef struct GtkTimelineClass GtkTimelineClass;
+
+typedef enum {
+  GTK_TIMELINE_DIRECTION_FORWARD,
+  GTK_TIMELINE_DIRECTION_BACKWARD
+} GtkTimelineDirection;
+
+typedef enum {
+  GTK_TIMELINE_PROGRESS_LINEAR,
+  GTK_TIMELINE_PROGRESS_EASE,
+  GTK_TIMELINE_PROGRESS_EASE_IN,
+  GTK_TIMELINE_PROGRESS_EASE_OUT,
+  GTK_TIMELINE_PROGRESS_EASE_IN_OUT
+} GtkTimelineProgressType;
+
+struct GtkTimeline
+{
+  GObject parent_instance;
+  gpointer priv;
+};
+
+struct GtkTimelineClass
+{
+  GObjectClass parent_class;
+
+  void (* started)           (GtkTimeline *timeline);
+  void (* finished)          (GtkTimeline *timeline);
+  void (* paused)            (GtkTimeline *timeline);
+
+  void (* frame)             (GtkTimeline *timeline,
+                             gdouble     progress);
+
+  void (* __gtk_reserved1) (void);
+  void (* __gtk_reserved2) (void);
+  void (* __gtk_reserved3) (void);
+  void (* __gtk_reserved4) (void);
+};
+
+
+GType                   gtk_timeline_get_type          (void) G_GNUC_CONST;
+
+GtkTimeline *           gtk_timeline_new               (guint                    duration);
+GtkTimeline *           gtk_timeline_new_for_screen    (guint                    duration,
+                                                        GdkScreen               *screen);
+
+void                    gtk_timeline_start             (GtkTimeline             *timeline);
+void                    gtk_timeline_pause             (GtkTimeline             *timeline);
+void                    gtk_timeline_rewind            (GtkTimeline             *timeline);
+
+gboolean                gtk_timeline_is_running        (GtkTimeline             *timeline);
+guint                   gtk_timeline_get_elapsed_time  (GtkTimeline             *timeline);
+
+guint                   gtk_timeline_get_fps           (GtkTimeline             *timeline);
+void                    gtk_timeline_set_fps           (GtkTimeline             *timeline,
+                                                        guint                    fps);
+
+gboolean                gtk_timeline_get_loop          (GtkTimeline             *timeline);
+void                    gtk_timeline_set_loop          (GtkTimeline             *timeline,
+                                                        gboolean                 loop);
+
+guint                   gtk_timeline_get_duration      (GtkTimeline             *timeline);
+void                    gtk_timeline_set_duration      (GtkTimeline             *timeline,
+                                                         guint                    duration);
+
+GdkScreen *             gtk_timeline_get_screen        (GtkTimeline             *timeline);
+void                    gtk_timeline_set_screen        (GtkTimeline             *timeline,
+                                                        GdkScreen               *screen);
+
+GtkTimelineDirection    gtk_timeline_get_direction     (GtkTimeline             *timeline);
+void                    gtk_timeline_set_direction     (GtkTimeline             *timeline,
+                                                        GtkTimelineDirection     direction);
+
+gdouble                 gtk_timeline_get_progress      (GtkTimeline             *timeline);
+
+GtkTimelineProgressType gtk_timeline_get_progress_type (GtkTimeline             *timeline);
+void                    gtk_timeline_set_progress_type (GtkTimeline             *timeline,
+                                                        GtkTimelineProgressType  progress_type);
+
+
+G_END_DECLS
+
+#endif /* _GTK_TIMELINE_H__ */